/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxStylesheetCodec
 *
 * Codec for <mxStylesheet>s. This class is created and registered
 * dynamically at load time and used implicitely via <mxCodec>
 * and the <mxCodecRegistry>.
 */
var mxStylesheetCodec = mxCodecRegistry.register(
  (function () {
    var codec = new mxObjectCodec(new mxStylesheet());

    /**
     * Function: encode
     *
     * Encodes a stylesheet. See <decode> for a description of the
     * format.
     */
    codec.encode = function (enc, obj) {
      var node = enc.document.createElement(this.getName());

      for (var i in obj.styles) {
        var style = obj.styles[i];
        var styleNode = enc.document.createElement("add");

        if (i != null) {
          styleNode.setAttribute("as", i);

          for (var j in style) {
            var value = this.getStringValue(j, style[j]);

            if (value != null) {
              var entry = enc.document.createElement("add");
              entry.setAttribute("value", value);
              entry.setAttribute("as", j);
              styleNode.appendChild(entry);
            }
          }

          if (styleNode.childNodes.length > 0) {
            node.appendChild(styleNode);
          }
        }
      }

      return node;
    };

    /**
     * Function: getStringValue
     *
     * Returns the string for encoding the given value.
     */
    codec.getStringValue = function (key, value) {
      var type = typeof value;

      if (type == "function") {
        value = mxStyleRegistry.getName(value);
      } else if (type == "object") {
        value = null;
      }

      return value;
    };

    /**
     * Function: decode
     *
     * Reads a sequence of the following child nodes
     * and attributes:
     *
     * Child Nodes:
     *
     * add - Adds a new style.
     *
     * Attributes:
     *
     * as - Name of the style.
     * extend - Name of the style to inherit from.
     *
     * Each node contains another sequence of add and remove nodes with the following
     * attributes:
     *
     * as - Name of the style (see <mxConstants>).
     * value - Value for the style.
     *
     * Instead of the value-attribute, one can put Javascript expressions into
     * the node as follows if <mxStylesheetCodec.allowEval> is true:
     * <add as="perimeter">mxPerimeter.RectanglePerimeter</add>
     *
     * A remove node will remove the entry with the name given in the as-attribute
     * from the style.
     *
     * Example:
     *
     * (code)
     * <mxStylesheet as="stylesheet">
     *   <add as="text">
     *     <add as="fontSize" value="12"/>
     *   </add>
     *   <add as="defaultVertex" extend="text">
     *     <add as="shape" value="rectangle"/>
     *   </add>
     * </mxStylesheet>
     * (end)
     */
    codec.decode = function (dec, node, into) {
      var obj = into || new this.template.constructor();
      var id = node.getAttribute("id");

      if (id != null) {
        dec.objects[id] = obj;
      }

      node = node.firstChild;

      while (node != null) {
        if (!this.processInclude(dec, node, obj) && node.nodeName == "add") {
          var as = node.getAttribute("as");

          if (as != null) {
            var extend = node.getAttribute("extend");
            var style =
              extend != null ? mxUtils.clone(obj.styles[extend]) : null;

            if (style == null) {
              if (extend != null) {
                mxLog.warn(
                  "mxStylesheetCodec.decode: stylesheet " +
                    extend +
                    " not found to extend"
                );
              }

              style = new Object();
            }

            var entry = node.firstChild;

            while (entry != null) {
              if (entry.nodeType == mxConstants.NODETYPE_ELEMENT) {
                var key = entry.getAttribute("as");

                if (entry.nodeName == "add") {
                  var text = mxUtils.getTextContent(entry);
                  var value = null;

                  if (
                    text != null &&
                    text.length > 0 &&
                    mxStylesheetCodec.allowEval
                  ) {
                    value = mxUtils.eval(text);
                  } else {
                    value = entry.getAttribute("value");

                    if (mxUtils.isNumeric(value)) {
                      value = parseFloat(value);
                    }
                  }

                  if (value != null) {
                    style[key] = value;
                  }
                } else if (entry.nodeName == "remove") {
                  delete style[key];
                }
              }

              entry = entry.nextSibling;
            }

            obj.putCellStyle(as, style);
          }
        }

        node = node.nextSibling;
      }

      return obj;
    };

    // Returns the codec into the registry
    return codec;
  })()
);

/**
 * Variable: allowEval
 *
 * Static global switch that specifies if the use of eval is allowed for
 * evaluating text content. Default is true. Set this to false if stylesheets
 * may contain user input.
 */
mxStylesheetCodec.allowEval = true;
